#include "SRF.h"
#include "LRF.h"

SRF::SRF()
{
	for(int i = 0; i < SRF_STREAMS; i ++)
	{
		srf_bank[i] = new SRF_sub();
	}

	for(int i = 0; i < SRF_CLIENTS; i ++)
	{
		CyclesLeft[i] = 0;
		CyclesLeft[SRF_CLIENTS];
		Ready[i] = true;
		opCode[i] = SRF_NOP;
		loc[i] = 0;
		input_int[i] = 0;
		input_char[i] = 0x00;
		input_float[i] = 0.0f;
		output_int[i] = 0;
		output_char[i] = 0x00;
		output_float[i] = 0.0f;
		stream_num[i] = 0;
	}
	stream_ptr[0] = STREAM0;
	stream_ptr[1] = STREAM1;
}

int SRF::set_client(int client_num, int stream, int mem_loc, unsigned char input, int op_code)
{
	if (op_code == SRF_READ)
		opCode[client_num] = SRF_READ_CHAR;
	else if (op_code == SRF_WRITE)
		opCode[client_num] = SRF_WRITE_CHAR;

	input_char[client_num] = input;
	loc[client_num] = mem_loc;
	stream_num[client_num] = stream;

	return 1;
}

int SRF::set_client(int client_num, int stream, int mem_loc, int input, int op_code)
{
	if (op_code == SRF_READ)
		opCode[client_num] = SRF_READ_INT;
	else if (op_code == SRF_WRITE)
		opCode[client_num] = SRF_WRITE_INT;

	input_int[client_num] = input;
	loc[client_num] = mem_loc;
	stream_num[client_num] = stream;

	return 1;
}

int SRF::set_client(int client_num, int stream, int mem_loc, float input, int op_code)
{
	if (op_code == SRF_READ)
		opCode[client_num] = SRF_READ_FLOAT;
	else if (op_code == SRF_WRITE)
		opCode[client_num] = SRF_WRITE_FLOAT;

	input_float[client_num] = input;
	loc[client_num] = mem_loc;
	stream_num[client_num] = stream;

	return 1;
}

//UPDATING the 4k memory banks
int SRF::update()
{
	int rv = 1;

	for (int i = 0; i < SRF_CLIENTS; i++)
		rv = rv && update(i);

	return rv;
}

int SRF::update(int client)
{
	if(Ready[client])
	{
		if( SRF_NOP != opCode[client] )
		{
			switch (opCode[client])
			{
			case SRF_WRITE_CHAR:
				CyclesLeft[client] = SRF_DELAY;
				break;
			case SRF_WRITE_INT:
				CyclesLeft[client] = SRF_DELAY;
				break;
			case SRF_WRITE_FLOAT:
				CyclesLeft[client] = SRF_DELAY;
				break;
			case SRF_READ_CHAR:
				CyclesLeft[client] = SRF_DELAY;
				break;
			case SRF_READ_INT:
				CyclesLeft[client] = SRF_DELAY;
				break;
			case SRF_READ_FLOAT:
				CyclesLeft[client] = SRF_DELAY;
				break;
			}

			Ready[client] = false;
			update(client);
		}
	}
	else // Not ready, processing operation
	{
		CyclesLeft[client]--;

		if( 0 == CyclesLeft[client] )
		{
			switch( opCode[client] )
			{
				case SRF_WRITE_CHAR:
					srf_bank[stream_num[client]]->write(loc[client], input_char[client]);
					break;
				case SRF_WRITE_INT:
					srf_bank[stream_num[client]]->write(loc[client], input_int[client]);
					break;
				case SRF_WRITE_FLOAT:
					srf_bank[stream_num[client]]->write(loc[client], input_float[client]);
					break;
				case SRF_READ_CHAR:
					srf_bank[stream_num[client]]->read(loc[client], output_char[client]);
					break;
				case SRF_READ_INT:
					srf_bank[stream_num[client]]->read(loc[client], output_int[client]);
					break;
				case SRF_READ_FLOAT:
					srf_bank[stream_num[client]]->read(loc[client], output_float[client]);
			}

			Ready[client] = true;
		}
	}
	return CyclesLeft[client];
}

int SRF::getOutput(int client_num, unsigned char& rv)
{
	rv = output_char[client_num];
	return Ready[client_num];
}

int SRF::getOutput(int client_num, int& rv)
{
	rv = output_int[client_num];
	return Ready[client_num];
}

int SRF::getOutput(int client_num, float& rv)
{
	rv = output_float[client_num];
	return Ready[client_num];
}

bool SRF::isReady(int client_num)
{
	return Ready[client_num];
}

void SRF::data_in(LRF* lrf[8], int lrf_loc)
{
	int loc;
	int temp;
	loc = stream_ptr[0];

	for (int i = 0; i < 8; i++)
	{
		set_client(i, i, loc, (int) 0, SRF_READ);
		update(i);
		getOutput(i, temp);
		lrf[i]->write(lrf_loc, temp);
	}
	stream_ptr[0] += 4;
}

void SRF::data_out(LRF* lrf[8], int lrf_loc)
{
	int loc;
	int temp;
	loc = stream_ptr[1];

	for (int i = 0; i < 8; i++)
	{
		lrf[i]->read(lrf_loc, temp);
		set_client(i, i, loc, temp, SRF_WRITE);
		update(i);
	}
	stream_ptr[1] += 4;
}

void SRF::init_data_in(unsigned char* init, unsigned int init_size)
{
	for (unsigned int i = 0; i < (init_size/8); i=i+4)
	{
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[0]->write(i+j, *init);
			init++;
		}
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[1]->write(i+j, *init);
			init++;
		}
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[2]->write(i+j, *init);
			init++;
		}
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[3]->write(i+j, *init);
			init++;
		}
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[4]->write(i+j, *init);
			init++;
		}
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[5]->write(i+j, *init);
			init++;
		}
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[6]->write(i+j, *init);
			init++;
		}
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[7]->write(i+j, *init);
			init++;
		}
	}
}

void SRF::get_data_out(unsigned char* init, unsigned int init_size)
{
	for (unsigned int i = 0; i < (init_size/8); i=i+4)
	{
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[0]->read(STREAM1+i+j, *init);
			init++;
		}
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[1]->read(STREAM1+i+j, *init);
			init++;
		}
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[2]->read(STREAM1+i+j, *init);
			init++;
		}
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[3]->read(STREAM1+i+j, *init);
			init++;
		}
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[4]->read(STREAM1+i+j, *init);
			init++;
		}
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[5]->read(STREAM1+i+j, *init);
			init++;
		}
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[6]->read(STREAM1+i+j, *init);
			init++;
		}
		for (int j = 0; j < 4 ; j++)
		{
			srf_bank[7]->read(STREAM1+i+j, *init);
			init++;
		}
	}
}
